package lincen.javame.game.tetris.pieces;

import lincen.javame.game.tetris.Stack;
import lincen.javame.light.util.Tool;

/**
 * 方块类:
 * 该类是绘制到画布上的主要游戏组件
 * 有左旋方法, 有移动方法
 * 本类的移动变化是通过控制偏移量来实现平移变化的
 * 而实际的四个块是固定的!
 * 即实际的块始终在大小为4 x 4 的矩阵里
 * @author Administrator
 *
 */
public class Tetris {

	/**
	 * 矩形块x, y偏移量
	 */
	private int dx, dy;

	/**
	 * 阶
	 */
	private int stage;

	/**
	 * 四个块
	 */
	private boolean [] [] point;

	public static Tetris getRandomTetris() {
		Tetris t;
		int r = Tool.getRandomInt(7);
		
		if(r >= 5) {
			t = new Tetris(4);
		} else {
			t = new Tetris(3);
		}
		
		t.setShape(r);
		
		r = Tool.getRandomInt(3);
		while(--r >= 0) {
			t.turnLeft();
		}
		return t;
	}

	public int getStage() {
		return this.stage;
	}

	/**
	 * 平移
	 * @param dx
	 * @param dy
	 */
	public void move(int dx, int dy) {
		this.dx += dx;
		this.dy += dy;
	}

	/**
	 * 逆时针转动90度
	 * 绕点(1, 1) 旋转
	 */
	public void turnLeft() {
		turnLeft(1, 2);
	}

	/**
	 * 顺时针旋转90度
	 * 绕点(1, 1)旋转
	 */
	public void turnRight() {
		turnRight(1, 2);
	}

	/**
	 * 获得点集
	 * @return
	 */
	public boolean [] [] getPoint() {
		return this.point;
	}

	/**
	 * 判断是否和Stack发生碰撞
	 * @param stack
	 * @return
	 */
	public boolean isCollidesWith(Stack stack) {
		for(int y = 0; y < getStage(); y++) {
			for (int x = 0; x < getStage(); x++) {
				if(
						this.point[y] [x] &&
						y + dy >= 0 && y + dy < stack.getRow() &&
						x + dx >= 0 && x + dx < stack.getCol() &&
						stack.getPoints() [y + dy] [x + dx]
				) {
					return true;
				}
			}
		}
		return false;
	}



	/**
	 * 初始化各个方块
	 * @param xn 第一个方块的横坐标
	 * @param yn 第一个方块的纵坐标
	 */
	protected final void set(
			int x1, int y1, 
			int x2, int y2, 
			int x3, int y3, 
			int x4, int y4
	) {
		this.point[x1][y1] = true;
		this.point[x2][y2] = true;
		this.point[x3][y3] = true;
		this.point[x4][y4] = true;
	}

	/**
	 * 获得X偏移量
	 * @return
	 */
	public int getDx() {
		return this.dx;
	}

	/**
	 * 获得Y偏移量
	 * @return
	 */
	public int getDy() {
		return this.dy;
	}

	/**
	 * 获得最左端的点的横坐标
	 * @return
	 */
	public int getLeft() {
		for (int x = 0; x < this.point[0].length; x++) {
			if(isColHaveElement(x)) {
				return x + this.getDx();
			}
		}

		return getStage() + this.getDx() + 1;
	}

	/**
	 * 获得最右端点的横坐标
	 * @return
	 */
	public int getRight() {
		for (int x = this.point[0].length - 1; x >= 0; x--) {
			if(isColHaveElement(x)) {
				return x + this.getDx();
			}
		}

		return this.getDx() - 1;
	}

	/**
	 * 获得最下端点的纵坐标
	 * @return
	 */
	public int getDown() {
		for (int y = this.point.length - 1; y >= 0; y--) {
			if(isRowHaveElement(y)) {
				return y + this.getDy();
			}
		}

		return getStage() + this.getDy() + 1;
	}

	/**
	 * 初始化形状为阶数为stage的方块
	 */
	Tetris(int stage) {
		this.stage = stage;
		this.point = new boolean[this.getStage()][this.getStage()];
	}

	/**
	 * 设置方块的形状
	 * 前置条件:
	 * 方块只有0 - 6七种形状
	 * @param i
	 */
	private void setShape(int i) {
		switch (i) {
		case 0://一点一横
			set(
					1, 0, 
					0, 1, 
					1, 1,
					2, 1
			);
			break;
	
		case 1://锄头(左)
			set(
					0, 0, 
					1, 0, 
					2, 0, 
					0, 1
			);
			break;
	
		case 2://锄头(右)
			set(
					0, 0, 
					0, 1, 
					1, 1,
					2, 1
			);
			break;
	
		case 3://Z字形(左)
			set(
					0, 0, 
					1, 0, 
					1, 1,
					2, 1
			);
			break;
	
		case 4://Z字形(右)
			set(
					1, 0, 
					2, 0, 
					0, 1,
					1, 1
			);
			break;
	
		case 5://石头
			set(
					1, 1, 
					2, 1, 
					1, 2, 
					2, 2
			);
			break;
	
		default://棍子
			set(
					1, 0, 
					1, 1, 
					1, 2, 
					1, 3
			);
			break;
		}
	}

	/**
	 * 绕点x, y逆时针旋转90度
	 * @param x
	 * @param y
	 */
	private void turnLeft(int x, int y) {
		Tool.rotateLeft90(this.point);
	}

	/**
	 * 绕点x, y顺时针旋转90度
	 * @param x
	 * @param y
	 */
	private void turnRight(int x, int y) {
		Tool.rotateRight90(this.point);
	}

	/**
	 * 判断第x列是否包含元素
	 * @param x
	 * @return
	 */
	private boolean isColHaveElement(int x) {
		for (int y = 0; y < this.point.length; y++) {
			if(this.point[y][x]) {
				return true;
			}
		}

		return false;
	}

	/**
	 * 判断第y行是否包含元素
	 * @param y
	 * @return
	 */
	private boolean isRowHaveElement(int y) {
		for (int x = 0; x < this.point.length; x++) {
			if(this.point[y][x]) {
				return true;
			}
		}
		return false;
	}
}
